package com.ikingtech.datav.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ikingtech.datav.exception.ComponentExceptionInfo;
import com.ikingtech.datav.mapper.ComponentMapper;
import com.ikingtech.datav.model.entity.ComponentDO;
import com.ikingtech.datav.model.request.ComponentDTO;
import com.ikingtech.datav.model.request.ComponentSearchDTO;
import com.ikingtech.datav.model.result.ComponentVO;
import com.ikingtech.datav.utils.Util;
import com.ikingtech.framework.sdk.base.model.PageResult;
import com.ikingtech.framework.sdk.context.exception.FrameworkException;
import com.ikingtech.framework.sdk.utils.Tools;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 组件表(ComponentDO)服务实现类
 *
 * @author fucb
 * @since 2024-02-22 09:28:43
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ComponentService extends ServiceImpl<ComponentMapper, ComponentDO> {

    /**
     * 分页查询
     *
     * @param queryParam 筛选条件
     * @return 查询结果
     */
    public PageResult<ComponentDO> selectByPage(ComponentSearchDTO queryParam) {
        return PageResult.build(this.page(new Page<>(queryParam.getPage(), queryParam.getRows()), Wrappers.<ComponentDO>lambdaQuery()
                .like(Tools.Str.isNotBlank(queryParam.getName()), ComponentDO::getName, queryParam.getName())
                .eq(Tools.Str.isNotBlank(queryParam.getId()), ComponentDO::getId, queryParam.getId())
                .eq(Tools.Str.isNotBlank(queryParam.getProjectId()), ComponentDO::getProjectId, queryParam.getProjectId())
                .eq(Tools.Str.isNotBlank(queryParam.getScreenId()), ComponentDO::getScreenId, queryParam.getScreenId())
                .eq(Tools.Str.isNotBlank(queryParam.getParentId()), ComponentDO::getParentId, queryParam.getParentId())
                .eq(Objects.nonNull(queryParam.getHided()), ComponentDO::getHided, queryParam.getHided())
                .eq(Objects.nonNull(queryParam.getHovered()), ComponentDO::getHovered, queryParam.getHovered())
                .eq(Objects.nonNull(queryParam.getIsDialog()), ComponentDO::getIsDialog, queryParam.getIsDialog())
                .eq(Objects.nonNull(queryParam.getIsPublic()), ComponentDO::getIsPublic, queryParam.getIsPublic())
                .eq(Tools.Str.isNotBlank(queryParam.getTemplateId()), ComponentDO::getTemplateId, queryParam.getTemplateId())
                .eq(Tools.Str.isNotBlank(queryParam.getComponentType()), ComponentDO::getComponentType, queryParam.getComponentType())
                .like(Tools.Str.isNotBlank(queryParam.getAlias()), ComponentDO::getAlias, queryParam.getAlias())
                .eq(Objects.nonNull(queryParam.getVersion()), ComponentDO::getVersion, queryParam.getVersion())));
    }

    /**
     * 查询详情
     *
     * @param id 主键
     * @return 数据详情
     */
    public ComponentVO getInfo(String id) {
        ComponentDO entity = this.baseMapper.selectById(id);
        if (null == entity) {
            throw new FrameworkException(ComponentExceptionInfo.COMPONENT_NOT_FOUND);
        }
        return Tools.Bean.copy(entity, ComponentVO.class);
    }

    /**
     * 新增
     *
     * @param param 实例对象
     */
    @Transactional(rollbackFor = Exception.class)
    public void add(ComponentDTO param) {
        this.baseMapper.insert(this.extracted(param));
    }

    public ComponentDO extracted(ComponentDTO param) {
        ComponentDO component = BeanUtil.copyProperties(param, ComponentDO.class);
        component.setAnimate(JSONUtil.toJsonStr(param.getAnimate()));
        component.setApis(JSONUtil.toJsonStr(param.getApis()));
        component.setApiData(JSONUtil.toJsonStr(param.getApiData()));
        component.setAttr(JSONUtil.toJsonStr(param.getAttr()));
        component.setBgImg(JSONUtil.toJsonStr(param.getBgImg()));
        component.setConfig(JSONUtil.toJsonStr(param.getConfig()));
        component.setDialog(JSONUtil.toJsonStr(param.getDialog()));
        component.setDisActions(JSONUtil.toJsonStr(param.getDisActions()));
        component.setEvents(JSONUtil.toJsonStr(param.getEvents()));
        component.setScaling(JSONUtil.toJsonStr(param.getScaling()));
        component.setChildren(JSONUtil.toJsonStr(param.getChildren()));
        return component;
    }

    /**
     * 修改
     *
     * @param param 实例对象
     */
    public void edit(ComponentDTO param) {
        if (!this.exist(param.getId())) {
            throw new FrameworkException(ComponentExceptionInfo.COMPONENT_NOT_FOUND);
        }

        ComponentDO component = BeanUtil.copyProperties(param, ComponentDO.class);
        this.baseMapper.updateById(component);
    }

    /**
     * 删除
     *
     * @param id 数据id
     */
    public void delete(String id) {
        this.baseMapper.deleteById(id);
    }

    public boolean exist(String id) {
        return this.baseMapper.exists(Wrappers.<ComponentDO>lambdaQuery().eq(ComponentDO::getId, id));
    }

    /**
     * 转换返回对象, 数据库中存储的内容为JSON字符串,返回时需转换为实体
     *
     * @param list 数据库实体列表
     * @return 转换后的VO列表
     */
    public List<ComponentVO> convertBatchVO(List<ComponentDO> list) {
        return Tools.Coll.convertList(list, this::convertVO);
    }

    public ComponentVO convertVO(ComponentDO entityVO) {
        return new ComponentVO()
                .setId(entityVO.getId())
                .setScreenId(entityVO.getScreenId())
                .setSortOrder(entityVO.getSortOrder())
                .setType(entityVO.getType())
                .setAlias(entityVO.getAlias())
                .setName(entityVO.getName())
                .setChildren(Util.Json.toBean(entityVO.getChildren()))
                .setLocked(entityVO.getLocked())
                .setParentId(entityVO.getParentId())
                .setHided(entityVO.getHided())
                .setIcon(entityVO.getIcon())
                .setImg(entityVO.getImg())
                .setAttr(Util.Json.toBean(entityVO.getAttr()))
                .setConfig(Util.Json.toBean(entityVO.getConfig()))
                .setApis(Util.Json.toBean(entityVO.getApis()))
                .setApiData(Util.Json.toBean(entityVO.getApiData()))
                .setAnimate(Util.Json.toBean(entityVO.getAnimate()))
                .setBgImg(Util.Json.toBean(entityVO.getBgImg()))
                .setScaling(Util.Json.toBean(entityVO.getScaling()))
                .setEvents(Util.Json.toBean(entityVO.getEvents()))
                .setSelected(entityVO.getSelected())
                .setHovered(entityVO.getHovered())
                .setBgAnimation(entityVO.getBgAnimation())
                .setDialog(Util.Json.toBean(entityVO.getDialog()))
                .setIsDialog(entityVO.getIsDialog())
                .setVersion(entityVO.getVersion())
                .setIsPublic(entityVO.getIsPublic())
                .setProjectId(entityVO.getProjectId())
                .setTemplateId(entityVO.getTemplateId())
                .setDisActions(Util.Json.toBean(entityVO.getDisActions()))
                .setComponentType(entityVO.getComponentType())
                .setCreateBy(entityVO.getCreateBy())
                .setCreateName(entityVO.getCreateName())
                .setCreateTime(entityVO.getCreateTime())
                .setUpdateBy(entityVO.getUpdateBy())
                .setUpdateName(entityVO.getUpdateName())
                .setUpdateTime(entityVO.getUpdateTime())

                ;
    }


    public List<ComponentDO> getListByScreenId(String screenId) {
        LambdaQueryWrapper<ComponentDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ComponentDO::getScreenId, screenId);
        return this.list(queryWrapper);
    }

    public List<ComponentDO> getListByScreenIds(List<String> screenId) {
        LambdaQueryWrapper<ComponentDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(ComponentDO::getScreenId, screenId);
        return this.list(queryWrapper);
    }

    public void removeByScreenId(String id) {
        LambdaQueryWrapper<ComponentDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ComponentDO::getScreenId, id);
        remove(queryWrapper);
    }

    /**
     * 迭代删除所有的子列表
     *
     * @param list 列表ID
     */
    @Transactional(rollbackFor = Exception.class)
    public void iterativeDeletionComponent(List<String> list) {
        if (list == null || list.isEmpty()) {
            return; // 验证输入，避免不必要的操作
        }

        Queue<String> queue = new LinkedList<>(list);
        while (!queue.isEmpty()) {
            List<String> batchList = new ArrayList<>(queue.size());
            batchList.addAll(queue); // 准备当前批次的ID
            queue.clear(); // 清空队列，避免重复处理

            // 查询当前批次ID对应的子项ID
            List<ComponentDO> childList = lambdaQuery()
                    .select(ComponentDO::getId)
                    .in(ComponentDO::getParentId, batchList)
                    .list();

            // 将子项ID加入队列，准备下一轮处理
            queue.addAll(childList.stream().map(ComponentDO::getId).toList());

            // 一次性删除当前批次的ID，减少数据库交互
            removeBatchByIds(batchList);
        }
    }

    public List<ComponentDO> convertBatchModel(List<ComponentVO> list) {
        return Tools.Coll.convertList(list, entityVO -> {
            ComponentDO entity = Tools.Bean.copy(entityVO, ComponentDO.class);
            entity.setAnimate(Tools.Json.toJsonStr(entity.getAnimate()));
            entity.setApis(Tools.Json.toJsonStr(entity.getApis()));
            entity.setApiData(Tools.Json.toJsonStr(entity.getApiData()));
            entity.setAttr(Tools.Json.toJsonStr(entity.getAttr()));
            entity.setBgImg(Tools.Json.toJsonStr(entity.getBgImg()));
            entity.setConfig(Tools.Json.toJsonStr(entity.getConfig()));
            entity.setDialog(Tools.Json.toJsonStr(entity.getDialog()));
            entity.setDisActions(Tools.Json.toJsonStr(entity.getDisActions()));
            entity.setEvents(Tools.Json.toJsonStr(entity.getEvents()));
            entity.setScaling(Tools.Json.toJsonStr(entity.getScaling()));
            entity.setChildren(Tools.Json.toJsonStr(entity.getChildren()));
            return entity;
        });
    }

    public void saveBatch(List<ComponentVO> componentList) {
        this.saveBatch(convertBatchModel(componentList));
    }
}
